package YAPserver.logic;

import java.util.ArrayList;
import java.util.HashMap;

import YAPserver.gameObjects.AbstractBall;
import YAPserver.gameObjects.AbstractGameObject;
import YAPserver.gameObjects.GameBall;
import YAPserver.gameObjects.Mod;
import YAPserver.gameObjects.Slider;
import YAPserver.gameObjects.GameWall;

/**
 * The GameModel defines the rules of YAP
 * There can be different rules e.g. the speed of the ball might increment over time
 * This Interface defines which methods must be implemented
 * The GamePlay class has a GameModel
 * @author Daniel
 *
 */
public interface GameModel {
	/**
	 * Adds a GameBall to the game. When implementing this method, one can choose
	 * how the ball will appear in the field.
	 * @param balls an arrayList of gameBalls to which another gameBall will be added
	 */
	public void addBall(ArrayList<GameBall> balls);
	/**
	 * Adds a Mod to the game. When implementing this method, one can choose
	 * how the Mod will appear in the field.
	 * @param modsMoving an arrayList of mods to which another mod will be added
	 * @param gameMod the gameModifier of the gamePlay which is needed in the argument to construct a new mod
	 */
	public void addMod(ArrayList<Mod> modsMoving, GameModifier gameMod);
	/**
	 * Gives a player a slider and a wall and sets the player as observer of both.
	 * In this method the sliders are also created. So the arrayList of sliders is empty, but the arrayList of walls is not.
	 * @param players a hashMap of players
	 * @param playerSliders a hashMap whose key is the player's id and the other Integer is the WallNumber
	 * @param sliders an empty arrayList of sliders
	 * @param walls an arrayList of walls
	 */
	public void assignPlayers(HashMap<Integer, Player> players, HashMap<Integer, Integer> playerSliders,
			ArrayList<Slider> sliders, ArrayList<GameWall> walls);
	/**
	 * Gives a player a slider and a wall and sets the player as observer of both.
	 * In this method the sliders are also created. So the arrayList of sliders is empty, but the arrayList of walls is not.
	 * @param players a hashMap of players
	 * @param sliders an empty arrayList of sliders
	 * @param walls an arrayList of walls
	 */
	public void assignPlayers(HashMap<Integer, Player> players, ArrayList<Slider> sliders, ArrayList<GameWall> walls);
	/**
	 * Tests if there is a collision between an abstract ball and any other gameObject. Returns true if there is a collision
	 * and false if there is not.
	 * @param ball ballAbstract with which to test collisions
	 * @param objects an arrayList of objects with which to test collisions
	 * @return true if there was a collision and otherwise false
	 */
	public boolean ballCollisions(AbstractBall ball, ArrayList<? extends AbstractGameObject> objects);
	/**
	 * Checks all collisions for all balls and objects. A common implementation of this method is to use ballCollisions(BallAbstract, ArrayList)
	 * for each ballAbstract.
	 * @param balls an arrayList of gameBalls
	 * @param modsMoving an arrayList of mods
	 * @param walls an arrayList of walls
	 * @param sliders an arrayList of sliders
	 * @see #ballCollisions(AbstractBall, ArrayList)
	 */
	public void checkCollisions(ArrayList<GameBall> balls, ArrayList<Mod> modsMoving, ArrayList<GameWall> walls, ArrayList<Slider> sliders);
	/**
	 * Creates a mod that is randomly chosen from a list of mods.
	 * @param modsMoving an arrayList of moving mods to which another mod is added
	 * @param gameMod the gameModifier of the gamePlay which is needed in the argument to construct a new mod
	 */
	public void createMod(ArrayList<Mod> modsMoving, GameModifier gameMod);
	/**
	 * Deletes balls that are no longer in play.
	 * @param balls the arrayList of gameBalls
	 * @param mods the arrayList of mods
	 */
	public void deleteBall(ArrayList<GameBall> balls, ArrayList<Mod> mods);
	/**
	 * Deletes players that are no longer in play and removes all the links.
	 * @param players arrayList of players
	 * @param sliders arrayList of sliders
	 * @param in input from which the link to the specified player will be removed
	 * @param gamePlay gamePlay to which the players and sliders belong
	 */
	public void deletePlayer(HashMap<Integer, Player> players, ArrayList<Slider> sliders, Input in, GamePlay gamePlay);
	/**
	 * Moves all sliders.
	 * @param players arrayList of players whose sliders will be moved
	 */
	public void moveSliders(HashMap<Integer, Player> players);
	/**
	 * Moves all abstract balls.
	 * @param balls arrayList of gameBalls to be moved
	 * @param modsMoving arrayList of mods to be moved
	 */
	public void moveBalls(ArrayList<GameBall> balls, ArrayList<Mod> modsMoving);
	/**
	 * Ticks all activated Mods. When their tickCount is at 0 then they are deactivated and remove themselves from the list of active mods.
	 * @param modsActive arrayList of active mods
	 */
	public void tickActiveMods(ArrayList<Mod> modsActive);
}
